using System;
using Schedule;
using BlackHen.Threading;

namespace TaskLib
{
    /// <summary>
    /// This is an <see cref="WorkItem"/> for a Task that needs to be performed
    /// </summary>
    class Task : WorkItem
    {

        #region Constructors

        /// <summary>
        /// Create a new Task with a filename to load
        /// </summary>
        /// <param name="pluginFilename">The filename of the plugin to load.</param>
        /// <param name="className">The name of the class (type) to load.</param>
        /// <exception cref="ArgumentException" />
        public Task(string pluginFilename, string className)
        {
            _log.DebugFormat(Properties.Resources.Msg_Task_Constructor1, pluginFilename, className);
            _plugin = TaskPluginInterface.Utilities.GetPlugin(pluginFilename, className);

            if (_plugin == null)
            {
                throw new ArgumentException(string.Format(Properties.Resources.Exception_FileNotAPlugin, pluginFilename), Properties.Resources.Parameter_PluginFilename);
            }
        }

        /// <summary>
        /// Create a new Task with the plugin.
        /// </summary>
        /// <param name="plugin">A plugin to load</param>
        public Task(TaskPluginInterface.ITaskPlugin plugin)
        {
            _log.DebugFormat(Properties.Resources.Msg_Task_Constructor2, plugin.Name);
            _plugin = plugin;
            if (_plugin == null)
            {
                throw new ArgumentNullException(Properties.Resources.Parameter_Plugin);
            }
        }

        #endregion Constructors

        #region Destructors
        /// <summary>
        /// Releases unmanaged resources and performs other cleanup operations before the
        /// <see cref="Task"/> is reclaimed by garbage collection.
        /// </summary>
        ~Task()
        {
            _log.DebugFormat(Properties.Resources.Msg_Task_Destructor, _plugin.Name, DateTime.Now);
            _timer.Stop();
            _timer = null;
            _plugin = null;
        }
        #endregion Destructors

        #region Private Variables

        private TaskPluginInterface.ITaskPlugin _plugin;
        private ScheduleTimer _timer = new ScheduleTimer();
        private static readonly log4net.ILog _log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        #endregion Private Variables

        public override void Perform()
        {

            _log.DebugFormat(Properties.Resources.Msg_Perform_Start, _plugin.Name);
            // Setup the event handlers
            _timer.Elapsed += Execute_Plugin;
            _timer.Error += HandleException;

            // Setup the Schedule.
            foreach (IScheduledItem schedule in _plugin.Schedule)
            {
                _timer.AddEvent(schedule);
            }

            // Start the timer.
            _timer.Start();
            _log.DebugFormat(Properties.Resources.Msg_Perform_ScheduleTimer, _plugin.Name);

        }

        /// <summary>
        /// Returns a reference to the plugin
        /// </summary>
        public TaskPluginInterface.ITaskPlugin Plugin
        {
            get { return _plugin; }
        }

        #region Events

        /// <summary>
        /// Calls the <c>Plugin's</c> Execute Method.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Execute_Plugin(object sender, ScheduledEventArgs e)
        {
            _log.InfoFormat(Properties.Resources.Msg_Task_EventExecutePlugin, _plugin.Name);
            _plugin.Execute();
        }

        /// <summary>
        /// Handles Errors raised by the Timer
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void HandleException(object sender, ExceptionEventArgs e)
        {
            string err = string.Format(Properties.Resources.Msg_Task_EventHandleException, _plugin.Name);
            _log.Error(err, e.Error);
        }

        #endregion Events
    }
}
